package com.assisjrs.jpaandroid.persistence;

import javax.transaction.TransactionRequiredException;

public interface EntityManager {

	/**
	 * Make an entity instance managed and persistent.
	 *
	 * @param entity
	 * @throws EntityExistsException
	 *             if the entity already exists. (The EntityExistsException may
	 *             be thrown when the persist operation is invoked, or the
	 *             EntityExistsException or another PersistenceException may be
	 *             thrown at flush or commit time.)
	 * @throws IllegalStateException
	 *             if this EntityManager has been closed.
	 * @throws IllegalArgumentException
	 *             if not an entity
	 * @throws TransactionRequiredException
	 *             if invoked on a container-managed entity manager of type
	 *             PersistenceContextType.TRANSACTION and there is no
	 *             transaction.
	 */
	void persist(Entity entity);

	/**
	 * Merge the state of the given entity into the current persistence context.
	 *
	 * @param entity
	 * @return the instance that the state was merged to
	 * @throws IllegalStateException
	 *             if this EntityManager has been closed.
	 * @throws IllegalArgumentException
	 *             if instance is not an entity or is a removed entity
	 * @throws TransactionRequiredException
	 *             if invoked on a container-managed entity manager of type
	 *             PersistenceContextType.TRANSACTION and there is no
	 *             transaction.
	 */
	<T extends Entity> T merge(T entity);

	/**
	 * Remove the entity instance.
	 *
	 * @param entity
	 * @throws IllegalStateException
	 *             if this EntityManager has been closed.
	 * @throws IllegalArgumentException
	 *             if not an entity or if a detached entity
	 * @throws TransactionRequiredException
	 *             if invoked on a container-managed entity manager of type
	 *             PersistenceContextType.TRANSACTION and there is no
	 *             transaction.
	 */
	void remove(Entity entity);

	/**
	 * Find by primary key.
	 *
	 * @param entityClass
	 * @param primaryKey
	 * @return the found entity instance or null if the entity does not exist
	 * @throws IllegalStateException
	 *             if this EntityManager has been closed.
	 * @throws IllegalArgumentException
	 *             if the first argument does not denote an entity type or the
	 *             second argument is not a valid type for that entity's primary
	 *             key
	 */
	<T extends Entity> T find(Class<T> entityClass, Long primaryKey);

	/**
	 * Get an instance, whose state may be lazily fetched. If the requested
	 * instance does not exist in the database, throws
	 * {@link EntityNotFoundException} when the instance state is first
	 * accessed. (The persistence provider runtime is permitted to throw
	 * {@link EntityNotFoundException} when {@link #getReference} is called.)
	 *
	 * The application should not expect that the instance state will be
	 * available upon detachment, unless it was accessed by the application
	 * while the entity manager was open.
	 *
	 * @param entityClass
	 * @param primaryKey
	 * @return the found entity instance
	 * @throws IllegalStateException
	 *             if this EntityManager has been closed.
	 * @throws IllegalArgumentException
	 *             if the first argument does not denote an entity type or the
	 *             second argument is not a valid type for that entity's primary
	 *             key
	 * @throws EntityNotFoundException
	 *             if the entity state cannot be accessed
	 */
	<T extends Entity> T getReference(Class<T> entityClass, Long primaryKey);

	/**
	 * Refresh the state of the instance from the database, overwriting changes
	 * made to the entity, if any.
	 *
	 * @param entity
	 * @throws IllegalStateException
	 *             if this EntityManager has been closed.
	 * @throws IllegalArgumentException
	 *             if not an entity or entity is not managed
	 * @throws TransactionRequiredException
	 *             if invoked on a container-managed entity manager of type
	 *             PersistenceContextType.TRANSACTION and there is no
	 *             transaction.
	 * @throws EntityNotFoundException
	 *             if the entity no longer exists in the database.
	 */
	void refresh(Entity entity);

	/**
	 * Create an instance of Query for executing a named query (in the Java
	 * Persistence query language or in native SQL).
	 *
	 * @param name
	 *            the name of a query defined in metadata
	 * @return the new query instance
	 * @throws IllegalStateException
	 *             if this EntityManager has been closed.
	 * @throws IllegalArgumentException
	 *             if a query has not been defined with the given name
	 */
	public Query createNamedQuery(String name);

	/**
	 * Create an instance of Query for executing a native SQL statement, e.g.,
	 * for update or delete.
	 *
	 * @param sqlString
	 *            a native SQL query string
	 * @return the new query instance
	 * @throws IllegalStateException
	 *             if this EntityManager has been closed.
	 */
	public Query createNativeQuery(String sqlString);

	/**
	 * Create an instance of Query for executing a native SQL query.
	 *
	 * @param sqlString
	 *            a native SQL query string
	 * @param resultClass
	 *            the class of the resulting instance(s)
	 * @return the new query instance
	 * @throws IllegalStateException
	 *             if this EntityManager has been closed.
	 */
	public Query createNativeQuery(String sqlString, Class<? extends Entity> resultClass);

	/**
	 * Returns the resource-level transaction object. The EntityTransaction
	 * instance may be used serially to begin and commit multiple transactions.
	 *
	 * @return EntityTransaction instance
	 * @throws IllegalStateException
	 *             if invoked on a JTA EntityManager.
	 */
	public EntityTransaction getTransaction();

	/**
	 * Indicate to the EntityManager that a JTA transaction is active. This
	 * method should be called on a JTA application managed EntityManager that
	 * was created outside the scope of the active transaction to associate it
	 * with the current JTA transaction.
	 *
	 * @throws IllegalStateException
	 *             if this EntityManager has been closed.
	 * @throws TransactionRequiredException
	 *             if there is no transaction.
	 */
	public void joinTransaction();

	/**
	 * Return the underlying provider object for the EntityManager, if
	 * available. The result of this method is implementation specific.
	 *
	 * @throws IllegalStateException
	 *             if this EntityManager has been closed.
	 */
	public Object getDelegate();
}
